package com.meiyuetao.myt.es.agent.web.action;

import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import lab.s2jh.core.annotation.MetaData;
import lab.s2jh.core.exception.DataAccessDeniedException;
import lab.s2jh.core.pagination.GroupPropertyFilter;
import lab.s2jh.core.pagination.PropertyFilter;
import lab.s2jh.core.pagination.PropertyFilter.MatchType;
import lab.s2jh.core.security.AclService;
import lab.s2jh.core.security.AuthContextHolder;
import lab.s2jh.core.service.BaseService;
import lab.s2jh.core.service.Validation;
import lab.s2jh.core.web.rest.Jackson2LibHandler;
import lab.s2jh.core.web.view.OperationResult;

import org.apache.commons.lang3.StringUtils;
import org.apache.struts2.rest.HttpHeaders;
import org.springframework.beans.factory.annotation.Autowired;

import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.google.common.collect.Maps;
import com.meiyuetao.myt.core.constant.VoucherStateEnum;
import com.meiyuetao.myt.core.web.MytBaseController;
import com.meiyuetao.myt.finance.entity.AccountSubject;
import com.meiyuetao.myt.finance.service.AccountSubjectService;
import com.meiyuetao.myt.partner.entity.Partner;
import com.meiyuetao.myt.sale.entity.ExpressDataTemplate;
import com.meiyuetao.myt.sale.entity.SaleDelivery;
import com.meiyuetao.myt.sale.entity.SaleDelivery.DeliveryProcessTypeEnum;
import com.meiyuetao.myt.sale.entity.SaleDeliveryDetail;
import com.meiyuetao.myt.sale.entity.SaleDeliveryPic;
import com.meiyuetao.myt.sale.service.ExpressDataTemplateService;
import com.meiyuetao.myt.sale.service.SaleDeliveryService;
import com.opensymphony.xwork2.interceptor.ParameterNameAware;

@MetaData("分销代理商的销售单管理")
public class SaleDeliveryController extends MytBaseController<SaleDelivery, Long> implements ParameterNameAware {

    // private final Logger logger =
    // LoggerFactory.getLogger(SaleDeliveryController.class);

    @Autowired
    private SaleDeliveryService saleDeliveryService;
    @Autowired
    private ExpressDataTemplateService expressDataTemplateService;
    @Autowired
    private AclService aclService;
    @Autowired
    private AccountSubjectService accountSubjectService;

    @Override
    protected BaseService<SaleDelivery, Long> getEntityService() {
        return saleDeliveryService;
    }

    @Override
    protected void setupDetachedBindingEntity(Long id) {
        bindingEntity = getEntityService().findDetachedOne(id, "saleDeliveryPics");
    }

    @MetaData(value = "按客户汇总订单数")
    public HttpHeaders findByGroupCustomerOrder() {
        setModel(findByGroupAggregate("customerProfile.id", "customerProfile.nickName", "customerProfile.trueName", "sum(totalAmount)", "customerProfile.mobilePhone",
                "customerProfile.deliveryAddr", "count(customerProfile.id)"));
        return buildDefaultHttpHeaders();
    }

    public Map<String, String> getReferenceSourceMap() {
        return this.findMapDataByDataDictPrimaryKey("MYT_SALE_DELIVERY_ORDER_SOURCE");
    }

    public Map<Long, String> getExpressDataTemplatesMap() {
        Map<Long, String> dataMap = new LinkedHashMap<Long, String>();
        GroupPropertyFilter groupPropertyFilter = GroupPropertyFilter.buildDefaultAndGroupFilter();
        groupPropertyFilter.forceAnd(new PropertyFilter(MatchType.EQ, "agentPartner", getLogonPartner()));
        List<ExpressDataTemplate> expressDataTemplates = expressDataTemplateService.findByFilters(groupPropertyFilter);
        for (ExpressDataTemplate item : expressDataTemplates) {
            dataMap.put(item.getId(), item.getDisplay());
        }
        return dataMap;
    }

    @MetaData(value = "付款会计科目数据")
    public Map<Long, String> getPaymentAccountSubjects() {
        Map<Long, String> datas = Maps.newLinkedHashMap();
        Iterable<AccountSubject> items = accountSubjectService.findPaymentAccountSubjects();
        for (AccountSubject item : items) {
            datas.put(item.getId(), item.getDisplay());
        }
        return datas;
    }

    @Override
    protected void checkEntityAclPermission(SaleDelivery entity) {
        // 限定只能访问登录用户所在商家的数据
        String aclCodePrefix = aclService.getLogonUserAclCodePrefix();
        Partner agentPartner = entity.getAgentPartner();
        if (agentPartner != null && StringUtils.isNotBlank(aclCodePrefix)) {
            String agentPartnerCode = agentPartner.getCode();
            if (!agentPartnerCode.startsWith(aclCodePrefix)) {
                throw new DataAccessDeniedException();
            }
        }
    }

    @Override
    protected void appendFilterProperty(GroupPropertyFilter groupPropertyFilter) {
        groupPropertyFilter.forceAnd(new PropertyFilter(MatchType.NN, "auditDate", true));
        groupPropertyFilter.forceAnd(new PropertyFilter(MatchType.NU, "redwordDate", true));
        // 限制只显示指派时间小于当前时间的单子
        groupPropertyFilter.forceAnd(new PropertyFilter(MatchType.LT, "agentAssignDate", new Date()));
        // 限定只能访问登录用户所在商家的数据
        String aclCodePrefix = aclService.getLogonUserAclCodePrefix();
        if (StringUtils.isNotBlank(aclCodePrefix)) {
            groupPropertyFilter.forceAnd(new PropertyFilter(MatchType.BW, "agentPartner.code", aclCodePrefix));
        }
    }

    @Override
    @MetaData("查询")
    public HttpHeaders findByPage() {
        // 根据当前功能的业务场景设定过滤敏感信息的JSON序列化输出
        /*
         * Jackson2LibHandler.setJsonPropertyFilter(SimpleBeanPropertyFilter.
         * filterOutAllExcept("voucher","agentAssignDate", "agentAcceptDate",
         * "lastOperationSummary", "referenceSource", "referenceVoucher",
         * "totalCostAmount", "customerProfile.*"));
         */
        Jackson2LibHandler.setJsonPropertyFilter(SimpleBeanPropertyFilter.filterOutAllExcept("id", "voucher", "agentAssignDate", "agentAcceptDate", "commodityAmount",
                "chargeLogisticsAmount", "totalAmount", "receivePerson", "logisticsNo", "mobilePhone", "deliveryAddr", "logisticsAmount", "agentAssignDatePassDuration"));
        return super.findByPage();
    }

    @MetaData("行项数据")
    public HttpHeaders saleDeliveryDetails() {
        /*
         * Jackson2LibHandler.setJsonPropertyFilter(SimpleBeanPropertyFilter.
         * serializeAllExcept("costPrice", "costAmount", "commodity.price",
         * "commodity.costPrice", "saleDelivery.totalCostAmount",
         * "saleDelivery.payedAmount",
         * "commodity.commodityVaryPrice.lastSalePrice",
         * "commodity.commodityVaryPrice.lastPurchasePrice",
         * "commodity.defaultStorageLocation.addr", "storageLocation.addr",
         * "profitAmount", "profitRate", "returnQuantity"));
         */

        Jackson2LibHandler.setJsonPropertyFilter(SimpleBeanPropertyFilter.filterOutAllExcept("id", "measureUnit", "quantity", "price", "gift", "originalAmount", "discountRate",
                "discountAmount", "amount", "commodity", "display", "sku", "title"));
        List<SaleDeliveryDetail> saleDeliveryDetails = bindingEntity.getSaleDeliveryDetails();

        setModel(buildPageResultFromList(saleDeliveryDetails));
        return buildDefaultHttpHeaders();
    }

    @Override
    public HttpHeaders doSave() {

        List<SaleDeliveryPic> saleDeliveryPices = bindingEntity.getSaleDeliveryPics();
        if (saleDeliveryPices != null && saleDeliveryPices.size() > 0) {
            for (SaleDeliveryPic saleDeliveryPic : saleDeliveryPices) {
                saleDeliveryPic.setSaleDelivery(bindingEntity);
            }
        }

        return super.doSave();
    }

    public String isDisallowDelivery() {
        if (VoucherStateEnum.REDW.equals(bindingEntity.getVoucherState())) {
            return "已红冲的不能修改";
        }
        if (bindingEntity.isNotNew() && bindingEntity.getDeliveryTime() != null) {
            return "已快递发货，不允许再修改";
        }
        return null;
    }

    public HttpHeaders doDelivery() {
        saleDeliveryService.deliverySave(bindingEntity);
        setModel(OperationResult.buildSuccessResult("发货完成"));
        return buildDefaultHttpHeaders();
    }

    @MetaData("是否允许代理商发货")
    public String isDisallowAgentDelivery() {
        if (bindingEntity.getAgentAcceptDate() == null) {
            return "请先接单，再发货";
        }
        if (VoucherStateEnum.REDW.equals(bindingEntity.getVoucherState())) {
            return "已红冲";
        }

        return null;
    }

    public HttpHeaders doAgentDelivery() {
        Validation.isTrue(bindingEntity.getDeliveryTime() == null, "已经发货完成");
        Validation.isTrue(getLogonPartner().equals(bindingEntity.getAgentPartner()), "无权对其他分销商的销售单作‘发货’操作");
        Validation.isTrue(bindingEntity.getAgentAcceptDate() != null, "还未接单，不能发货");
        bindingEntity.setProcessType(DeliveryProcessTypeEnum.DELIVERY);
        saleDeliveryService.deliverySave(bindingEntity);
        setModel(OperationResult.buildSuccessResult("发货完成"));
        return buildDefaultHttpHeaders();
    }

    public HttpHeaders doAssign() {
        bindingEntity.setAgentAcceptDate(null);
        bindingEntity.setAgentPartnerNotified(null);

        saleDeliveryService.save(bindingEntity);
        setModel(OperationResult.buildSuccessResult("指派操作完成"));
        return buildDefaultHttpHeaders();
    }

    public HttpHeaders doAccept() {
        Validation.isTrue(bindingEntity.getDeliveryTime() == null, "已经发货完成，接单无效");
        String aclCode = AuthContextHolder.getAclCode();
        Collection<SaleDelivery> entities = this.getEntitiesByParameterIds();
        for (SaleDelivery entity : entities) {

            if (entity.getAgentPartner() != null && entity.getAgentPartner().getCode().equals(aclCode) && entity.getAgentAcceptDate() == null) {
                entity.setAgentAcceptDate(new Date());
                entity.setProcessType(DeliveryProcessTypeEnum.ACCEPT);
                saleDeliveryService.save(entity);
            }
        }
        if (bindingEntity != null) {
            /*
             * //检测本次提交表单没有用户已confirm确认标识，则进行相关预警校验检查 if
             * (postNotConfirmedByUser()) { List<String> messages =
             * Lists.newArrayList(); if
             * (!getLogonPartner().equals(bindingEntity.getAgentPartner()))
             * {//不是同一分销商提示用户 messages.add("当前销售单已指派分销商：" +
             * bindingEntity.getAgentPartner().getAbbr() + ",确认取消指派自己处理？"); } if
             * (messages.size() > 0) {
             * setModel(OperationResult.buildConfirmResult("销售单数据处理警告",
             * messages)); //直接返回使用户进行Confirm确认 return
             * buildDefaultHttpHeaders(); } }
             */
            Validation.isTrue(getLogonPartner().equals(bindingEntity.getAgentPartner()) || bindingEntity.getAgentAcceptDate() == null, "其他分销商已经接单");
            bindingEntity.setAgentAcceptDate(new Date());
            bindingEntity.setProcessType(DeliveryProcessTypeEnum.ACCEPT);
            saleDeliveryService.save(bindingEntity);
        }
        setModel(OperationResult.buildSuccessResult("接单操作完成"));
        return buildDefaultHttpHeaders();
    }

    public HttpHeaders doReject() {
        Partner partner = getLogonPartner().getParent();
        Validation.isTrue(partner != null, "已无上级可退");
        bindingEntity.setAgentPartner(partner);
        bindingEntity.setAgentAssignDate(new Date());
        bindingEntity.setAgentAcceptDate(null);
        saleDeliveryService.save(bindingEntity);
        setModel(OperationResult.buildSuccessResult("退回上前操作完成"));
        return buildDefaultHttpHeaders();
    }

    private static String[] acceptableParameterNames = new String[] { "receivePerson", "mobilePhone", "postCode", "deliveryAddr", "logistics.id", "logisticsNo", "logisticsAmount",
            "deliveryTime", "agentPartner.id", "expressDataTemplate.id", "deliveryType", "title", "agentAssignDate", "saleDeliveryPics[*].id", "saleDeliveryPics[*].picUrl",
            "saleDeliveryPics[*].picIndex" };

    /**
     * 对于需要给外部用户访问的Controller为了避免用户非法篡改数据 以 @see ParameterNameAware
     * 形式设置自动绑定参数白名单
     */
    @Override
    public boolean acceptableParameterName(String parameterName) {
        boolean acceptable = acceptableParameterName(acceptableParameterNames, parameterName);
        // logger.debug(" - Parameter {}: acceptable= {}", parameterName,
        // acceptable);
        return acceptable;
    }

}